package com.shareyi.simpleserver.servlet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.shareyi.simpleserver.core.HttpRequest;
import com.shareyi.simpleserver.servlet.config.FilterBean;
import com.shareyi.simpleserver.servlet.config.FilterMappingBean;
import com.shareyi.simpleserver.servlet.config.ListenerBean;
import com.shareyi.simpleserver.servlet.config.ServletBean;
import com.shareyi.simpleserver.servlet.config.ServletMappingBean;
import com.shareyi.simpleserver.servlet.config.WebAppBean;
import com.shareyi.simpleserver.servlet.config.WebAppParseUtil;

public class WebApplication {

	private static Log logger=LogFactory.getLog(WebApplication.class);
	private WebAppBean webAppBean;
	private Map<String,Filter> filterMap;
	private Map<String,Servlet> servletMap;
	private Boolean inited=false;
	private Servlet defaultFileServlet;
	private ApplicationContext applicationContext;
	private List<ServletContextListener> servletContextListeners;
	
	
	public void init(String webConfigPath){
		if(!inited){
			filterMap=new HashMap<String, Filter>();
			servletMap=new HashMap<String, Servlet>();
			try {
				webAppBean=WebAppParseUtil.parseWebConfig(webConfigPath);
				this.applicationContext=new ApplicationContext();
				Map contextMap=webAppBean.getContextParamMap();
				this.applicationContext.setParamMap(contextMap);

				//initial Listener
				initalListener();
				//initial Filter 
				initalFilter();
				
				inited=true;
			} catch (Exception e) {
				e.printStackTrace();
				logger.error("初始化simpleServer失败",e);
			}
			
		}
	}
	

	/**
	 * inital the application listeners,we only support ServletContextListener interface
	 */
	private void initalListener() {
		List<ListenerBean> listenerBeans=webAppBean.getListenderList();
		if(listenerBeans!=null&&listenerBeans.size()!=0){
			servletContextListeners=new ArrayList<ServletContextListener>(listenerBeans.size());
			for (ListenerBean listenerBean : listenerBeans) {
				String listenerClassName=listenerBean.getListenerClass();
				Object o=null;
				try {
					o = Class.forName(listenerClassName).newInstance();
					if(o instanceof ServletContextListener){
						ServletContextListener listener=(ServletContextListener) o;
						servletContextListeners.add(listener);
						listener.contextInitialized(applicationContext);
					}else{
						logger.error("filter definenation class ["+listenerClassName+"] is not a ServletContextListener!");
					}
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("instance ServletContextListener class ["+listenerClassName+"] failed!");
				}
			}
		}
	}


	/**
	 * 初始化拦截器，servlet在调用的时候再初始化
	 */
	private void initalFilter() {
		Map<String, FilterBean> filterBeanMap=webAppBean.getFilterBeanMap(); 
		Set<String> keySet=filterBeanMap.keySet();
		for (String key : keySet) {
			FilterBean filterBean=filterBeanMap.get(key);
			String filterClass=filterBean.getFilterClass();
			Object o=null;
			try {
				o = Class.forName(filterClass).newInstance();
				if(o instanceof Filter){
					Filter filter=(Filter) o;
					try {
						FilterConfig filterConfig=new FilterConfig();
						filterConfig.setFilterName(filterBean.getFilterName());
						filterConfig.setParamMap(filterBean.getConfigParams());
						filterConfig.setApplicationContext(applicationContext);
						filter.init(filterConfig);
						filterMap.put(key, filter);
						} catch (ServletException e) {
						logger.error("init filter ["+key+"] failed!");
					}
					
				}else{
					logger.error("filter definenation class ["+filterClass+"] is not a filter!");
				}
			} catch (Exception e) {
				e.printStackTrace();
				logger.error("instance filter class ["+filterClass+"] failed!");
			}
		}
		
	}
	
	
	
	/**
	 * Get servlet instance by request url, the servlet must have declared in web.xml file 
	 * @param url
	 * @return
	 */
	public Servlet getServletByUrl(String url){
	
		List<ServletMappingBean> mappingBeans=webAppBean.getServletMappingList();
		if(!mappingBeans.isEmpty()){
			for (ServletMappingBean servletMappingBean : mappingBeans) {
				if(PatternUtil.isMatchPattern(url, servletMappingBean.getUrlPattern()
						,servletMappingBean.getPatternType())){
					return this.getServlet(servletMappingBean.getServletName());
				}
			}
		}
		//如果为空，指定一个default Servlet
		if(defaultFileServlet==null){
			defaultFileServlet=new DefaultFileServlet();
		}
		
		return defaultFileServlet;
	}
	
	
	private Servlet getServlet(String servletName){
		Servlet servlet=servletMap.get(servletName);
		if(servlet==null){
			ServletBean servletBean=webAppBean.getServletBeanMap().get(servletName);
			if(servletBean==null){
				logger.error("servlet ["+servletName+"] definenation not found!");
			}else{
				String servletClass=servletBean.getServletClass();
				try {
					servlet=(Servlet) Class.forName(servletClass).newInstance();
					servlet.init(servletBean.getConfigParams());
					servletMap.put(servletName, servlet);
				} catch (Exception e) {
					logger.error("servlet ["+servletName+"]'s class not found ["+servletClass+"]");
				}
				
			}
		}
		return servlet;
	}
 
	
	/**
	 * Get the filter chain list by the request url and those rules which have been declared in web.xml
	 * @param request
	 * @return
	 */
	public List<Filter> getFilterListByRequest(HttpRequest request){
		List<Filter> filterList=new ArrayList<Filter>();
		List<FilterMappingBean> mappingBeanList=webAppBean.getFilterMappingList();
		if(!mappingBeanList.isEmpty()){
			for (FilterMappingBean filterMappingBean : mappingBeanList) {
				if(PatternUtil.isMatchPattern(request.getUrl(), filterMappingBean.getUrlPattern(),
						filterMappingBean.getPatternType())){
					List<String> dispatcherList=filterMappingBean.getDispatcherList();
					//验证拦截器的转发类型和请求相互匹配
					for (String dispatcherType : dispatcherList) {
						if(dispatcherType.equals(request.getDispatcherType())){
							filterList.add(filterMap.get(filterMappingBean.getFilterName()));
							break;
						}
					}
				}
			}
		}
		return filterList;
		
	}
 
 
	
public WebAppBean getWebAppBean() {
	return webAppBean;
}

public void setWebAppBean(WebAppBean webAppBean) {
	this.webAppBean = webAppBean;
}


public ApplicationContext getApplicationContext() {
	return applicationContext;
}


}
